package cn.elves.model.auth.service.impl;

import cn.elves.model.auth.entity.dto.AuthenticationDTO;
import cn.elves.model.auth.entity.dto.MenuNodeDTO;
import cn.elves.model.auth.entity.po.*;
import cn.elves.model.auth.service.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.elves.model.auth.entity.constant.MenuConstant.ROOT_NODE_ID;


@Service
public class AuthenticationServiceImpl implements AuthenticationService {


    @Resource
    private UserRoleRelationService userRoleRelationService;

    @Resource
    private RoleMenuRelationService roleMenuRelationService;

    @Resource
    private RoleInterfaceRelationService roleInterfaceRelationService;

    @Resource
    private MenuService menuService;

    @Resource
    private InterfaceService interfaceService;

    @Override
    public AuthenticationDTO selectAvailableMenu(Long userId) {

        List<UserRoleRelation> userRoleRelationList = userRoleRelationService.list(new QueryWrapper<UserRoleRelation>().eq("user_id", userId));
        if (CollectionUtils.isEmpty(userRoleRelationList)) {
            return new AuthenticationDTO();
        }

        List<RoleMenuRelation> roleMenuRelationList = roleMenuRelationService.list(new QueryWrapper<RoleMenuRelation>()
                .in("role_id", userRoleRelationList.stream().map(UserRoleRelation::getRoleId).collect(Collectors.toList())));
        if (CollectionUtils.isEmpty(roleMenuRelationList)) {
            return new AuthenticationDTO();
        }

        List<Menu> menuList = menuService.list(new QueryWrapper<Menu>().in("id",
                roleMenuRelationList.stream().map(RoleMenuRelation::getMenuId).collect(Collectors.toList())));
        if (CollectionUtils.isEmpty(menuList)) {
            return new AuthenticationDTO();
        }


        List<MenuNodeDTO> menuNodeDTOList = menuList.stream().map(this::buildMenuDTO).collect(Collectors.toList());
        List<MenuNodeDTO> menuNodeTree = buildMenuDTOTree(menuNodeDTOList);


        AuthenticationDTO authenticationDTO = new AuthenticationDTO();
        authenticationDTO.setMenuNodeDTOList(menuNodeTree);
        return authenticationDTO;
    }

    @Override
    public Boolean decideInterfaceAvailable(Long userId, String url, String method) {
        List<UserRoleRelation> userRoleRelationList = userRoleRelationService.list(new QueryWrapper<UserRoleRelation>().eq("user_id", userId));
        if (CollectionUtils.isEmpty(userRoleRelationList)) {
            return false;
        }

        List<RoleInterfaceRelation> roleInterfaceRelationList = roleInterfaceRelationService.list(new QueryWrapper<RoleInterfaceRelation>()
                .in("role_id", userRoleRelationList.stream().map(UserRoleRelation::getRoleId).collect(Collectors.toList())));
        if (CollectionUtils.isEmpty(roleInterfaceRelationList)) {
            return false;
        }

        List<Interface> interfaceList = interfaceService.list(new QueryWrapper<Interface>().in("id",
                        roleInterfaceRelationList.stream().map(RoleInterfaceRelation::getInterfaceId).collect(Collectors.toList()))
                .eq("url", url)
                .eq("method", method));


        return decideAvailable(interfaceList);
    }


    private Boolean decideAvailable(List<Interface> interfaceList) {
        return !CollectionUtils.isEmpty(interfaceList);
    }


    private MenuNodeDTO buildMenuDTO(Menu menu) {
        MenuNodeDTO menuNodeDTO = new MenuNodeDTO();
        BeanUtils.copyProperties(menu, menuNodeDTO);
        return menuNodeDTO;
    }

    private List<MenuNodeDTO> buildMenuDTOTree(List<MenuNodeDTO> menuNodeDTOList) {
        Map<Long, List<MenuNodeDTO>> parentIdNodeMap = menuNodeDTOList.stream().collect(Collectors.groupingBy(MenuNodeDTO::getParentId));
        for (MenuNodeDTO menuNodeDTO : menuNodeDTOList) {
            menuNodeDTO.setSubMenuList(parentIdNodeMap.getOrDefault(menuNodeDTO.getId(), new ArrayList<>()));
        }
        return menuNodeDTOList.stream().filter(this::decideIsRoot).collect(Collectors.toList());
    }

    private Boolean decideIsRoot(MenuNodeDTO menuNodeDTO) {
        return ROOT_NODE_ID.equals(menuNodeDTO.getParentId());
    }


}




